﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace FCMS.Collections
{
    [Serializable]
    public sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable
    {
        // Fields
        private IDictionary<TKey, TValue> dictionary;
        private bool isFixedSize;

        // Methods
        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
            : this(dictionary, true)
        {
        }

        public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary, bool makeCopy)
        {
            if (makeCopy)
            {
                this.dictionary = new Dictionary<TKey, TValue>(dictionary);
            }
            else
            {
                this.dictionary = dictionary;
            }
            this.isFixedSize = makeCopy;
        }

        public void Add(TKey key, TValue value)
        {
            throw GenerateReadOnlyException();
        }

        public void Clear()
        {
            throw GenerateReadOnlyException();
        }

        public bool ContainsKey(TKey key)
        {
            return this.dictionary.ContainsKey(key);
        }

        public bool Remove(TKey key)
        {
            throw GenerateReadOnlyException();
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> keyValuePair)
        {
            throw GenerateReadOnlyException();
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> keyValuePair)
        {
            if (this.ContainsKey(keyValuePair.Key))
            {
                TValue local = this[keyValuePair.Key];
                return local.Equals(keyValuePair.Value);
            }
            return false;
        }

        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            this.dictionary.CopyTo(array, arrayIndex);
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> keyValuePair)
        {
            throw GenerateReadOnlyException();
        }

        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
        {
            return this.dictionary.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.dictionary.GetEnumerator();
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            return this.dictionary.TryGetValue(key, out value);
        }

        // Properties
        public int Count
        {
            get
            {
                return this.dictionary.Count;
            }
        }

        public bool IsFixedSize
        {
            get
            {
                return this.isFixedSize;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return true;
            }
        }

        public TValue this[TKey key]
        {
            get
            {
                return this.dictionary[key];
            }
            set
            {
                throw GenerateReadOnlyException();
            }
        }

        public ICollection<TKey> Keys
        {
            get
            {
                return this.dictionary.Keys;
            }
        }

        public ICollection<TValue> Values
        {
            get
            {
                return this.dictionary.Values;
            }
        }

        private InvalidOperationException GenerateReadOnlyException()
        {
            return new InvalidOperationException("This dictionary is readonly.");
        }
    }

}
